package _2BeanFactory.beans.factory.support;

import _2BeanFactory.utils.ClassUtils;
import _2BeanFactory.utils.XMLReader;
import _2BeanFactory.beans.BeanDefinition;
import _2BeanFactory.beans.factory.BeanFactory;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 陈岳
 * @create 2019-01-17 16:40
 */
public class DefaultBeanFactory implements BeanFactory{

    /**
     * xml bean标签的id属性
     */
    public static final String ID_ATTRIBUTE = "id";
    /**
     * xml bean标签的class属性
     */
    public static final String CLASS_ATTRIBUTE = "class";

    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

    private Map<String, Object> beanInstanceMap = new ConcurrentHashMap<>();

    public DefaultBeanFactory(String configFile) throws DocumentException {
        loadBeanDefinition(configFile);
    }

    private void loadBeanDefinition(String configFile) {
        InputStream is = null;
        try {
            ClassLoader cl = ClassUtils.getDefaultClassLoader();
            is = cl.getResourceAsStream(configFile);
            SAXReader reader = new SAXReader();
            Document doc = reader.read(is);

            Element root = doc.getRootElement();
            Iterator<Element> iter = root.elementIterator();
            while(iter.hasNext()){
                Element ele = iter.next();
                String id = ele.attributeValue(ID_ATTRIBUTE);
                String beanClassName = ele.attributeValue(CLASS_ATTRIBUTE);
                BeanDefinition bd = new GenericBeanDefinition(id, beanClassName);
                this.beanDefinitionMap.put(id, bd);
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public BeanDefinition getBeanDifinition(String beanID) throws ClassNotFoundException {
        return this.beanDefinitionMap.get(beanID);
    }

    public Object getBean(String beanID) {
        BeanDefinition bd = this.beanDefinitionMap.get(beanID);
        if(bd == null){
            return null;
        }

        String beanClassName = bd.getBeanClassName();
        if (bd.isSingleton()) {
            if (beanInstanceMap.get(beanClassName) != null){
                return beanInstanceMap.get(beanClassName);
            }
        }
        return createBean(beanClassName);
    }

    private Object createBean(String beanClassName){
        try {
            Class clazz = Class.forName(beanClassName);
            return clazz.newInstance();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
}
